package com.mdinic.blogovi.front.common.coppableimage;

import java.awt.Rectangle;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.image.NonCachingImage;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.util.string.StringValue;

public abstract class CroppableImage extends NonCachingImage {

    private static final long serialVersionUID = 1L;

    private int minWidth, minHeight;

    /**
     * This constructor can be used if you have a img tag that has a src that
     * points to a PackageResource (which will be created and bind to the shared
     * resources) Or if you have a value attribute in your tag for which the
     * image factory can make an image.
     * 
     * @see org.apache.wicket.Component#Component(String)
     */
    public CroppableImage(final String id, final IModel cropAreaModel) {
        super(id, cropAreaModel);
        init();
    }

    /**
     * Constructs an image from an image resourcereference. That resource
     * reference will bind its resource to the current SharedResources.
     * 
     * If you are using non sticky session clustering and the resource reference
     * is pointing to a Resource that isn't guaranteed to be on every server,
     * for example a dynamic image or resources that aren't added with a
     * IInitializer at application startup. Then if only that resource is
     * requested from another server, without the rendering of the page, the
     * image won't be there and will result in a broken link.
     * 
     * @param id
     *            See Component
     * @param resourceReference
     *            The shared image resource
     */
    public CroppableImage(final String id, final IModel cropAreaModel, final ResourceReference resourceReference) {
        this(id, cropAreaModel, resourceReference, null);
        init();
    }

    /**
     * Constructs an image from an image resourcereference. That resource
     * reference will bind its resource to the current SharedResources.
     * 
     * If you are using non sticky session clustering and the resource reference
     * is pointing to a Resource that isn't guaranteed to be on every server,
     * for example a dynamic image or resources that aren't added with a
     * IInitializer at application startup. Then if only that resource is
     * requested from another server, without the rendering of the page, the
     * image won't be there and will result in a broken link.
     * 
     * @param id
     *            See Component
     * @param resourceReference
     *            The shared image resource
     * @param resourceParameters
     *            The resource parameters
     */
    public CroppableImage(final String id, final IModel cropAreaModel, final ResourceReference resourceReference,
            PageParameters resourceParameters) {
        super(id, cropAreaModel);
        setImageResourceReference(resourceReference, resourceParameters);
        init();
    }

    /**
     * Constructs an image directly from an image resource.
     * 
     * This one doesn't have the 'non sticky session clustering' problem that
     * the ResourceReference constructor has. But this will result in a non
     * 'stable' url and the url will have request parameters.
     * 
     * @param id
     *            See Component
     * 
     * @param imageResource
     *            The image resource
     */
    public CroppableImage(final String id, final IModel cropAreaModel, final IResource imageResource) {
        super(id, cropAreaModel);
        setImageResource(imageResource);
        init();
    }

    /**
     * Common initialisation shared by all constructors.
     */
    private void init() {
        System.out.println("CroppableImage.init()");
        setOutputMarkupId(true);
        add(new CroppableBehavior());
    }

    @Override
    public void renderHead(IHeaderResponse response) {

        // response.render(JavaScriptHeaderItem.forUrl("js/jquery-1.9.1.min.js"));
        response.render(JavaScriptHeaderItem.forUrl("js/cropper/prototype.js"));
        response.render(JavaScriptHeaderItem.forUrl("js/cropper/scriptaculous.js"));
        response.render(JavaScriptHeaderItem.forUrl("js/cropper/cropper.js"));
        response.render(CssHeaderItem.forUrl("js/cropper/cropper.css"));
    }

    /**
     * Called when the area to be cropped is changed.
     * 
     * @param target
     */
    public abstract void onCropAreaUpdate(AjaxRequestTarget target);

    /**
     * @return minimum width of crop area in pixels
     */
    public int getMinWidth() {
        return minWidth;
    }

    /**
     * Sets the minimum width of the crop area.
     * 
     * @param minWidth
     *            in pixels
     */
    public void setMinWidth(int minWidth) {
        this.minWidth = minWidth;
    }

    /**
     * @return minimum height of crop area in pixels
     */
    public int getMinHeight() {
        return minHeight;
    }

    /**
     * Sets the minimum height of the crop area.
     * 
     * @param minHeight
     *            in pixels
     */
    public void setMinHeight(int minHeight) {
        this.minHeight = minHeight;
    }

    private class CroppableBehavior extends AbstractDefaultAjaxBehavior {

        private static final long serialVersionUID = 1L;

        @Override
        public void renderHead(final Component component, final IHeaderResponse response) {
            System.out.println("renderHead for CroppableBehavior");
            super.renderHead(component, response);
            String javaScript = String.format("new Cropper.Img('%s', {"
                    + "\n onEndCrop: function(coords, dimensions) {%s}," + "\n minWidth: %d, minHeight: %d," + "\n});",
                    getComponent().getMarkupId(), getCallbackScript(), getMinWidth(), getMinHeight());
            response.render(OnDomReadyHeaderItem.forScript(javaScript));
        }

        @Override
        public CharSequence getCallbackScript() {
            String s = String.valueOf(super.getCallbackScript());
            return s.replace("\"", "'");
        }

        @Override
        public CharSequence getCallbackUrl() {
            System.out.println("getCallbackUrl for CroppableBehavior");
            String suffix = "&x=' + coords.x1 + '&y=' + coords.y1 + "
                    + "'&w=' + dimensions.width + '&h=' + dimensions.height + '";
            return super.getCallbackUrl() + suffix;
        }

        @Override
        protected void respond(AjaxRequestTarget target) {
            System.out.println("respond");
            Request request = RequestCycle.get().getRequest();

            StringValue parameterValue = request.getPostParameters().getParameterValue("x");
            if (parameterValue.isEmpty()) {
                return;
            }
            int x = parameterValue.toInt();
            int y = request.getPostParameters().getParameterValue("y").toInt();
            ;
            int w = request.getPostParameters().getParameterValue("w").toInt();
            int h = request.getPostParameters().getParameterValue("h").toInt();
            CroppableImage.this.setDefaultModelObject(new Rectangle(x, y, w, h));
            onCropAreaUpdate(target);
        }
    }
}
